package com.invengo.device;

import android.annotation.SuppressLint;
import android.app.Application;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.Log;

import androidx.annotation.NonNull;

import com.invengo.lib.system.device.type.DeviceType;
import com.invengo.library_rfid.VoiceManager;
import com.invengo.library_rfid.analyze.EPCAnalyzeFactory;
import com.invengo.library_rfid.analyze.EPCStrategy;
import com.invengo.library_rfid.analyze._EpcRuleTag;
import com.invengo.library_rfid.classify.AnalyzeImpl;
import com.invengo.library_rfid.classify.RfidModelImpl;
import com.invengo.library_rfid.device.IDevice;
import com.invengo.uhf.ConnectType;
import com.invengo.uhf.IReaderTagsMsgReceiver;
import com.invengo.uhf.RfidReader;
import com.invengo.uhf.TagMessage;

import java.util.ArrayList;
import java.util.List;

import java8.util.Optional;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

import invengo.javaapi.protocol.IRP1.IntegrateReaderManager;
import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import me.goldze.mvvmhabit.bus.RxBus;
import me.goldze.mvvmhabit.bus.RxSubscriptions;
import me.goldze.mvvmhabit.http.interceptor.logging.LocalLogUtil;
import me.goldze.mvvmhabit.utils.KLog;
import me.goldze.mvvmhabit.utils.ToastUtils;
import me.goldze.mvvmhabit.utils.cache.ACache;
import me.goldze.mvvmhabit.utils.cache.AKey;
import me.goldze.mvvmhabit.utils.constant.Constants;

public class DeviceHelper implements IDevice, IReaderTagsMsgReceiver {
    protected boolean isReading = false;
    protected RfidReader mReader;
    protected ExecutorService mThreadService;
    private HandsetRfidReaderGenerator mReaderGenerator;

    private AnalyzeImpl analyze = AnalyzeImpl.TO_BOOK; //解析类型，比如book，shelf，tid
    private EPCStrategy ruleStrategy; //标签解析方案
    private RfidModelImpl rfidModel;//标签类型更改
    private boolean isOpenVoice = true;
    private VoiceManager voiceManager;

    //    private _CacheTag fragmentTag;
    private String cacheKey;

    public VoiceManager getVoiceManager() {
        return voiceManager;
    }

    public static DeviceHelper instance;

    public static DeviceHelper getInstance() {
        if (instance == null) synchronized (DeviceHelper.class) {
            if (instance == null) {
                instance = new DeviceHelper();
            }
        }
        return instance;
    }


    private DeviceHelper() {
        ruleStrategy = EPCAnalyzeFactory.getInstance().getRuleStrategy();
        rfidModel = RfidModelImpl.getDefaultModel();
        System.out.println("设置默认模型及标签：[ " + ruleStrategy.getRule().getRuleName() + " ]  [ " + rfidModel.name() + " ]");
        isOpenVoice = ACache.getInstance().getAsBoolean(AKey.IS_OPEN_VOICE);
        mThreadService = Executors.newCachedThreadPool();
    }


    @Override
    public void init(Application application) {
        voiceManager = VoiceManager.getInstance(application);
        ParamerManager.getInstance().initDefaultConfig(application);
        RxSubscriptions.add(RxBus.getDefault().toObservable(_EpcRuleTag.class).subscribe(ruleTag -> {
            Log.w(getClass().getSimpleName(), "切换解析 模型 >>>： " + ruleTag.getRuleName());
            this.ruleStrategy = EPCAnalyzeFactory.getInstance().getEPCStrategy(ruleTag);
        }));
        RxSubscriptions.add(RxBus.getDefault().toObservable(AnalyzeImpl.class).subscribe(analyzeModel -> {
            Log.w(getClass().getSimpleName(), "图书层标切换 >>>： " + analyzeModel.getName());
            this.analyze = analyzeModel;
        }));
        RxSubscriptions.add(RxBus.getDefault().toObservable(RfidModelImpl.class).subscribe(rfidModel -> {
            Log.w(getClass().getSimpleName(), "切换标签  类型 >>>： " + rfidModel.getName());
            this.rfidModel = rfidModel;
        }));
        openDevice();
    }

    public AnalyzeImpl getAnalyze() {
        return analyze;
    }

    @Override
    public void openDevice() {
        checkInterval();
        mThreadService.execute(() -> {
            mReaderGenerator = new HandsetRfidReaderGenerator.Builder().setType(ConnectType.RS232).setPort(IntegrateReaderManager.getPortName()).setBaudrate(115200).build();
            long start = System.currentTimeMillis();
            boolean success = mReaderGenerator.connect();
            long time = System.currentTimeMillis() - start;
            LocalLogUtil.device2Log("设备链接时间:" + time + "毫秒");
            mReaderGenerator.setDeviceType(DeviceType.XC2908);
            mReader = mReaderGenerator.getRfidReader();
            mReaderGenerator.getRfidReader().powerOff();
            getDefaultPower();
            if (!success) {
                LocalLogUtil.device2Log("设备链接失败:" + mReaderGenerator.getDeviceType());
                throw new RuntimeException("设备无法连接");
            } else
                LocalLogUtil.device2Log("设备链接成功:" + mReaderGenerator.getDeviceType());
        });
    }

    @SuppressLint("NewApi")
    private void getDefaultPower() {
        new Thread(() -> {
            try {
                int[] powerMeter = (int[]) ACache.getInstance().getAsObject(AKey.RFID_POWER_METER);
                if (powerMeter == null)
                    powerMeter = getPowerMeter();
                if (powerMeter == null)
                    powerMeter = Constants.DEFAULT_POWERMETER;
                ACache.getInstance().put(AKey.RFID_POWER_METER, powerMeter);
                int[] pwoers = getPower();
                if (pwoers == null) {
                    Integer p = (Integer) Optional.ofNullable(ACache.getInstance().getAsObject(AKey.RFID_POWER)).orElse(20);
                    Observable.just(p)
                            .observeOn(AndroidSchedulers.mainThread()).subscribe(integer -> {
                                changePower(integer);
                            });
                    pwoers = new int[]{p};
                }
                ACache.getInstance().put(AKey.RFID_POWER, pwoers[0]);
            } catch (Exception e) {
                LocalLogUtil.device2Log("设备信息获取异常: " + e.getMessage());
                e.printStackTrace();
            }
        }).start();
    }

    private Disposable connectInterval;

    private void checkInterval() {
        if (connectInterval == null)
            connectInterval = Observable.interval(5000, TimeUnit.MILLISECONDS)
                    .subscribeOn(AndroidSchedulers.mainThread())
                    .subscribe(aLong -> {
//                        KLog.e("每隔5秒检查一下"+aLong);
                        RxBus.getDefault().post(checkReaderConnection());
                    });
    }


    @Override
    public void closeDevice() {
        mThreadService.execute(() -> {
            mReaderGenerator.disconnect();
        });
        if (connectInterval != null && !connectInterval.isDisposed())
            connectInterval.dispose();
    }


    @Override
    @SuppressLint("NewApi")
    public void startScan(String cacheKey) {
        this.cacheKey = cacheKey;
        List<String> strings = Optional.ofNullable(analyze.cache.get(cacheKey)).orElseGet(ArrayList::new);
        System.out.println("当前缓存[" + cacheKey + "] ==》" + strings);
        analyze.cache.put(cacheKey, strings);
        if (!isReading)
            mThreadService.execute(() -> {
                if (!checkReaderConnection()) {
                    RxBus.getDefault().post(false);
                    KLog.e("设备链接失败");
//                    ToastUtils.showShort("设备链接失败");
                    return;
                }
                mReader.addReaderTagsMsgReceiver(DeviceHelper.this);
                isReading = mReader.readTag6C(6, 0, 0);
            });
    }

    @Override
    public void stopScan() {
        if (isReading)
            mThreadService.execute(() -> {
                isReading = false;
                mReader.removeReaderTagsMsgReceiver(DeviceHelper.this);
                mReader.powerOff();
                mReader.powerOff();
            });
    }

    @Override
    public boolean checkReaderConnection() {
        if (mReader == null) {
            Log.e(getClass().getSimpleName(), "设备未连接");
            return false;
        }
        return mReader.getConnectStatus();
    }

    @Override
    public void changeAnalyzeModel(AnalyzeImpl analyze) {
        this.analyze = analyze;
    }

    @SuppressLint("NewApi")
    @Override
    public void cleanCache(String cacheKey) {
        Optional.ofNullable(analyze.cache.get(cacheKey)).ifPresent(list -> {
            System.out.println("取消第2-1步：清理[ " + cacheKey + " ] 缓存" + list.size());
            list.clear();
            System.out.println("取消第2-2步：清理后的缓存 [ " + cacheKey + " ] 缓存" + list.size());
        });
    }

    public List<String> getCache(String cacheKey) {
        return analyze.cache.get(cacheKey);
    }

    @Override
    public boolean isReading() {
        return isReading;
    }

    @Override
    public int[] getPowerMeter() {
        if (!checkReaderConnection()) {
            Log.e(getClass().getSimpleName(), "设备链接失败");
            return null;
        }
        return mReader.getPowerMeter();
    }

    @Override
    public int[] getPower() {
        if (!checkReaderConnection()) {
            Log.e(getClass().getSimpleName(), "设备链接失败");
            return null;
        }
        return mReader.getPowers();
    }

    @Override
    public List<String> getDeviceList() {
        return new ArrayList<>();
    }

    @Override
    public void changeVoice(boolean needVoice) {
        ACache.getInstance().put(AKey.IS_OPEN_VOICE, needVoice);
        if (needVoice) {
            DeviceHelper.getInstance().getVoiceManager().playBeep();
        }
        isOpenVoice = needVoice;
    }

    @SuppressLint("NewApi")
    @Override
    public void onReaderTagsMsgReceive(RfidReader rfidReader, TagMessage tagMessage) {
        if (rfidModel == RfidModelImpl.TID) {
            analyze.apply(tagMessage.getTid(), tagMessage.getEpc(), rfidModel, ruleStrategy, cacheKey);
        } else if (rfidModel == RfidModelImpl.EPC) {
            analyze.apply(tagMessage.getTid(), tagMessage.getEpc(), rfidModel, ruleStrategy, cacheKey);
        } else {
        }
    }


    @SuppressLint("NewApi")
    public void addTempCache(String cacheKey) {
        this.cacheKey = cacheKey;
        List<String> strings = Optional.ofNullable(analyze.cache.get(cacheKey)).orElseGet(ArrayList::new);
        System.out.println("当前缓存[" + cacheKey + "] ==》" + strings);
        analyze.cache.put(cacheKey, strings);
    }

    public void changePower(Integer integer) {
        mThreadService.execute(() -> {
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            if (isReading)
                stopScan();
            if (!checkReaderConnection()) {
                Log.e(getClass().getSimpleName(), "Reader is disconnected");
                return;
            }
            Message msg = new Message();
            mReader.powerOff();
            if (!mReader.setPowers(0, integer)) {
                msg.obj = false;
                LocalLogUtil.device2Log("设置功率失败：" + integer);
            } else {
                msg.obj = true;
                LocalLogUtil.device2Log("设置功率成功" + integer);
                ACache.getInstance().put(AKey.RFID_POWER, integer);
            }
            Looper.prepare();
            handler.handleMessage(msg);
            Looper.loop();
        });
    }

    Handler handler = new Handler(Looper.getMainLooper()) {
        @Override
        public void handleMessage(@NonNull Message msg) {
            if ((Boolean) msg.obj) {
                ToastUtils.showShort("设置功率成功");
            } else {
                ToastUtils.showShort("设置功率失败");
            }
        }
    };


    public void playVoice() {
        if (isOpenVoice)
            DeviceHelper.getInstance().getVoiceManager().playSuccessSound();
    }

    @Override
    public void playOhterVoice() {
        if (isOpenVoice)
            getVoiceManager().playFailureSound();
    }
}
